#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>


#define beep_cnt        1
#define beep_major      200
#define beep_minor      0
#define beep_name       "beep"


#define beepon      1
#define beepoff     0

#define CCM_CCGR1_BASE 			                    (0X020C406C)
#define SW_MUX_CTL_PAD_SNVS_TAMPER1_BASE        	(0X0229000C)            	
#define SW_PAD_CTL_PAD_SNVS_TAMPER1_BASE	        (0X02290050)		
#define GPIO5_DR_BASE 				                (0X020AC000)
#define GPIO5_GDIR_BASE 			                (0X020AC004)


static void __iomem *CCM_CCGR1_VIRT;
static void __iomem *SW_MUX_CTL_PAD_SNVS_TAMPER1_VIRT;
static void __iomem *SW_PAD_CTL_PAD_SNVS_TAMPER1_VIRT;
static void __iomem *GPIO5_DR_VIRT;
static void __iomem *GPIO5_GDIR_VIRT;




struct beep_dev {
    dev_t devid;                // 设备号
    struct cdev cdev;           // cdev
    struct class *class;        // 类
    struct device *device;      // 设备
    int major;                  // 主设备号
    int minor;                  // 次设备号
};
 
struct beep_dev beepdev;

void beep_switch(u8 sta) {
    u32 val = 0;
    if(sta == beepon) {
        val = readl(GPIO5_DR_VIRT);
        val &= ~(1<<1);
        writel(val, GPIO5_DR_VIRT);
    } else if(sta == beepoff) {
        val = readl(GPIO5_DR_VIRT);
        val |= (1<<1);
        writel(val, GPIO5_DR_VIRT);
    }
    
}

static int qdbeep_open(struct inode *inode, struct file *filp) {
    filp->private_data = &beepdev;
    printk("beep open\n");
    return 0;
}

static ssize_t qdbeep_read(struct file *filp, char __user *buf, size_t count, loff_t *offt) {
    printk("beep read\n");
    return 0;
}

static ssize_t qdbeep_write(struct file *filp, const char __user *buf, size_t count, loff_t *offt) {
    
    int ret = 0;
    unsigned char beepdata[1];
    unsigned char beepsta;

    ret = copy_from_user(beepdata, buf, count);
    if(ret<0) {
        printk("write data error.\r\n");
        return -EFAULT;
    }
    printk("write data success.\r\n");

    beepsta = beepdata[0];

    if(beepsta == beepoff ) {
        beep_switch(beepoff);
    } else if(beepsta==beepon) {
        beep_switch(beepon);
    }
    return 0;
}

static int qdbeep_release(struct inode *inode, struct file *filp) {
    printk("beep release\n");
    return 0;
}

static struct file_operations qdbeep_fops = {
    .owner = THIS_MODULE,
    .open = qdbeep_open,
    .read = qdbeep_read,
    .write = qdbeep_write,
    .release = qdbeep_release,
};


static int __init qdbeep_init(void) {
    int ret = 0;
    u32 val = 0;

    CCM_CCGR1_VIRT = ioremap(CCM_CCGR1_BASE, 4);
    SW_MUX_CTL_PAD_SNVS_TAMPER1_VIRT = ioremap(SW_MUX_CTL_PAD_SNVS_TAMPER1_BASE, 4);
    SW_PAD_CTL_PAD_SNVS_TAMPER1_VIRT = ioremap(SW_PAD_CTL_PAD_SNVS_TAMPER1_BASE, 4);
    GPIO5_DR_VIRT = ioremap(GPIO5_DR_BASE, 4);
    GPIO5_GDIR_VIRT = ioremap(GPIO5_GDIR_BASE, 4);

    val = readl(CCM_CCGR1_VIRT);
    val &= ~(3<<30);
    val |= (3<<30);
    writel(val, CCM_CCGR1_VIRT);
    printk("111;\r\n");

    writel(0, SW_MUX_CTL_PAD_SNVS_TAMPER1_VIRT);
    printk("2222,\r\n");
    writel(0x10B0, SW_PAD_CTL_PAD_SNVS_TAMPER1_VIRT);
    printk("333,\r\n");

    val = readl(GPIO5_GDIR_VIRT);
    val &= ~(1 << 1);	
	val |= (1 << 1);
    writel(val, GPIO5_GDIR_VIRT);
    printk("444\r\n");


    beepdev.devid = MKDEV(beep_major, beep_minor);
    ret = register_chrdev_region(beepdev.devid, beep_cnt, beep_name);
    if(ret<0) {
        printk("beep register error\n");
        return -1;
    }
    printk("555\r\n");
    beepdev.cdev.owner = THIS_MODULE;
    printk("666\r\n");
    cdev_init(&beepdev.cdev, &qdbeep_fops);
    printk("777\r\n");
    cdev_add(&beepdev.cdev, beepdev.devid, beep_cnt);
    printk("888\r\n");
    beepdev.class = class_create(THIS_MODULE, beep_name);
    if(IS_ERR(beepdev.class)) {
        printk("beep class error\n");
        unregister_chrdev_region(beepdev.devid, beep_cnt);
        cdev_del(&beepdev.cdev);
        return -1;
    }
    printk("999\r\n");
    beepdev.device = device_create(beepdev.class, NULL, beepdev.devid, NULL, beep_name);
    if(IS_ERR(beepdev.device)) {
        return -1;
    }
    printk("101010\r\n");
    return 0;


}

static void __exit qdbeep_exit(void) {
    cdev_del(&beepdev.cdev);
    unregister_chrdev_region(beepdev.devid, beep_cnt);
    device_destroy(beepdev.class, beepdev.devid);
    class_destroy(beepdev.class);
    iounmap(CCM_CCGR1_VIRT);
    iounmap(SW_MUX_CTL_PAD_SNVS_TAMPER1_VIRT);
    iounmap(SW_PAD_CTL_PAD_SNVS_TAMPER1_VIRT);
    iounmap(GPIO5_DR_VIRT);
    iounmap(GPIO5_GDIR_VIRT);
    printk("beep exit\n");
}

module_init(qdbeep_init);
module_exit(qdbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xby");